#pragma once
#include <iostream>
#include "Connection.hpp"
using namespace std;

class IOService
{
public:
    IOService(func_t func)
        : _func(func)
    {
    }

    void HandlerRecv(Connection *conn)
    {
        errno = 0;
        LOG(INFO, "now HandlerRecv begin n: %d\n", conn->Sockfd());
        while (1)
        {
            char buffer[1024];
            ssize_t n = recv(conn->Sockfd(), buffer, sizeof(buffer) - 1, 0);
            if (n <= 0)
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    // 出错
                    conn->_excepter(conn);
                    return; // 一定要返回，不然会走到下面的func
                }
            }
            else
            {
                buffer[n] = 0;
                string ret = conn->AppendIn(buffer);
                cout << "client# " << ret << endl;
            }
        }
        // 走到这里，处理报文，把它交给另一个类来构造出func
        _func(conn);
    }
    void HandlerSend(Connection *conn)
    {
        errno = 0;
        while (1)
        {
            ssize_t n = send(conn->Sockfd(), conn->Outbuffer().c_str(), conn->Outbuffer().size(), 0);
            if (n > 0)
            {
                // 每次写满，需要把已经写了的从缓冲区拿掉，下次就能从下个位置开始
                conn->OutbufferErase(n);
                if (conn->OutbufferEmpty())
                    break;
            }
            else if (n == 0)
                break;
            else
            {
                if (errno == EWOULDBLOCK || errno == EAGAIN)
                    break;
                else if (errno == EINTR)
                    return;
                else
                {
                    conn->_excepter(conn);
                    return;
                }
            }
        }
        // 走到这里，可能是写满了的问题，也可能是写完了，所以再判断
        // 写满了，那就设置对写事件关心即可
        if (!conn->OutbufferEmpty())
        {
            conn->_r->EnableReadWrite(conn->Sockfd(), true, true);
        }

        // 写完了，对写事件去关心
        else
        {
            conn->_r->EnableReadWrite(conn->Sockfd(), true, false);
        }
    }
    void HandlerExcept(Connection *conn)
    {
        errno = 0;
        LOG(INFO, "client quit: %d\n", conn->Sockfd());
        conn->_r->RemoveConnection(conn->Sockfd());
    }

private:
    func_t _func;
};